class Odca
{
  // Public Constructors
  public Odca(int length)
  {
    odca_length = length;
    odca_cells = new int[length + 4];
    odca_rule = new int[10];

    odca_start = 2;
    odca_end = length + 2;
  }

  // Public Member Functions
  public int getLength() { return odca_length; }
  public int getCell(int cell) { return odca_cells[cell + odca_start]; }

  public void reportRule()
  {
    int i;
    for (i = 0; i < 9; i++)
      {
	System.out.print(odca_rule[i]);
	System.out.print(", ");
      }
    System.out.print(odca_rule[9]);
    System.out.println();
  }

  public void randomize()
  {
    int i;
    for (i = odca_start; i < odca_end; i++)
      odca_cells[i] = (int) (4 * Math.random());
  }

  public void randomRule()
  {
    int i;
    for (i = 0; i < 10; i++)
      {
	odca_rule[i] = (int) (4 * Math.random());
      }
  }

  public void setRule(int rule[])
  {
    odca_rule = rule;
  }

  public void mutateRule()
  {
    int which = (int) (10 * Math.random());
    odca_rule[which] += 1;
    odca_rule[which] &= 3;
  }

  public void generate()
  {
    // Copy two cells at the end to before the beginning
    odca_cells[odca_start - 1] = odca_cells[odca_end - 1];
    odca_cells[odca_start - 2] = odca_cells[odca_end - 2];

    // Copy two cells at the beginning to past the end
    odca_cells[odca_end + 0] = odca_cells[odca_start + 0];
    odca_cells[odca_end + 1] = odca_cells[odca_start + 1];

    // Generate!
    int i;
    int previous = 0;;
    for (i = odca_start; i < odca_end; i++)
      {
	int sum = odca_cells[i - 1] + odca_cells[i] + odca_cells[i + 1];
	odca_cells[i - 1] = previous;
	previous = odca_rule[sum];
      }

    odca_cells[i - 1] = previous;
  }

  public int [] pix() { return odca_cells; }

  // Private Data Members
  private int odca_start;
  private int odca_end;

  private int odca_length;
  private int odca_cells[];
  private int odca_rule[];
}
